/*
 * This file is part of quickReminder, a software for gamers
 *
 * Copyright (C) 2006-2008 Lucas Romero
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.ComponentModel;
using System.IO;
using System.Collections;
using System.Threading;

namespace UserNotifier
{
    [Serializable]
    public class WarnModuleCollection
    {
        private List<WarnModule> m_Modules = new List<WarnModule>();

        private bool m_IgnoreWarnings = false;

        private TimerCollection m_Timers = new TimerCollection();

        [XmlIgnore]
        [Browsable(false)]
        public bool IgnoreWarnings
        {
            get { return m_IgnoreWarnings; }
            set { m_IgnoreWarnings = value; }
        }

        public void Load(string file)
        {
            m_File = file;
            XmlSerializer x = new XmlSerializer(this.GetType());
            using (StreamReader s = new StreamReader(file))
            {
                WarnModuleCollection tmp = (WarnModuleCollection)x.Deserialize(s);
                this.Modules = tmp.Modules;
                s.Close();
            }
        }

        public void OnGameProcessChanged(System.Diagnostics.Process process)
        {
            foreach (WarnModule m in m_Modules)
            {
                m.OnGameProcessChanged(process);
            }
        }

        public void TryLoad(string file)
        {
            try
            {
                Load(file);
            }
            catch{}
        }
        private string m_File;
        public void Save(string file)
        {
            XmlSerializer x = new XmlSerializer(this.GetType());
            using (StreamWriter s = new StreamWriter(file))
            {
                x.Serialize(s, this);
                s.Close();
            }
        }
        public void Save()
        {
            Save(m_File);
        }

        public WarnModule[] Modules
        {
            get
            {
                return m_Modules.ToArray();
            }
            set
            {
                m_Modules.Clear();
                m_Modules.AddRange(value);
            }
        }

        public void AddModule(WarnModule module)
        {
            m_Modules.Add(module);
        }

        public void RemoveModule(WarnModule module)
        {
            
            m_Modules.Remove(module);
            module.ActiveEvents = WarnEvents.None;
        }

        public void Warn(WarnEvents ev)
        {
            if (m_IgnoreWarnings)
                return;
            foreach(WarnModule m in m_Modules)
            {
                m.ActiveEvents |= ev;
            }
        }

        public void Warn(WarnEvents ev, int timeout)
        {
            if (m_IgnoreWarnings)
                return;
            Warn(ev);
            if (timeout != Timeout.Infinite)
                m_Timers.NewTimer(ev, new TimerCallback(UnWarn), timeout);
        }

        public ConsoleWarnModule getConsoleWarnModule()
        {
            foreach (WarnModule m in m_Modules)
                if (m.Type == WarnModuleTypes.ConsoleWarnModule)
                    return (ConsoleWarnModule)m;
            return null;
        }

        public OSDWarnModule getOSDWarnModule()
        {
            foreach (WarnModule m in m_Modules)
                if (m.Type == WarnModuleTypes.OSDWarnModule)
                    return (OSDWarnModule)m;
            return null;
        }

        public void UnWarn(object o)
        {
            UnWarn((WarnEvents)o);
        }

        public void UnWarn(WarnEvents ev)
        {
            if (m_IgnoreWarnings)
                return;
            foreach (WarnModule m in m_Modules)
            {
                m.ActiveEvents &= ~ev;
            }
        }

        public void Ignore()
        {
            m_IgnoreWarnings = true;
            Stop();
        }

        public void UnIgnore()
        {
            m_IgnoreWarnings = false;
        }

        public void Stop()
        {
            foreach (WarnModule m in m_Modules)
            {
                m.Stop();
            }
        }

        public WarnModuleCollection()
        {
            WarnModule m = new OSDWarnModule();
            m.AssignedEvents = WarnEvents.LowDiskspace | WarnEvents.NoAequitas | WarnEvents.NoReplay | WarnEvents.RestartReplay;
            m_Modules.Add(m);
        }

        public static WarnModule CreateModule(WarnModuleTypes module)
        {
            switch (module)
            {
                case WarnModuleTypes.ConsoleWarnModule:
                    return new ConsoleWarnModule(2000, 27005);
                case WarnModuleTypes.HWBeepWarnModule:
                    return new HWBeepWarnModule(5000, 1000, 400);
                case WarnModuleTypes.HWKeyboardBlink:
                    return new HWKeyboardBlink(1000, KeyboardLEDs.ScrollLock, 500);
                case WarnModuleTypes.OSDWarnModule:
                    return new OSDWarnModule(10);
                case WarnModuleTypes.SoundWarnModule:
                    return new SoundWarnModule(2000, "warn.wav");
                case WarnModuleTypes.SWKeyboardBlink:
                    return new SWKeyboardBlink(1000, KeyboardLEDs.CapsLock, 500);
                case WarnModuleTypes.CDTrayWarnModule:
                    return new CDTrayWarnModule(2000, 100);
                case WarnModuleTypes.ExternalWarnModule:
                    return new ExternalWarnModule(5000, @"C:\test.exe");
                case WarnModuleTypes.GammaWarnModule:
                    return new GammaWarnModule(1000, 50);
                case WarnModuleTypes.TeamChatWarnModule:
                    return new TeamChatWarnModule();
                default:
                    throw new NotSupportedException("Module not supported!");
            }
            return null;
        }
    }

    public class WarnTimer
    {
        private Timer m_Timer;
        private int m_Timeout;
        private WarnEvents m_Event;
        private TimerCallback callback;
        private TimerCollection m_Parent;
        public WarnEvents Event
        {
            get
            {
                return m_Event;
            }
        }
        public WarnTimer(TimerCollection parent, WarnEvents ev, TimerCallback Callback, int timeout)
        {
            callback = Callback;
            m_Parent = parent;
            m_Timeout = timeout;
            m_Timer = new Timer(new TimerCallback(CallbackWrapper), ev, timeout, Timeout.Infinite);
            m_Event = ev;
        }
        public void Reset()
        {
            m_Timer.Change(m_Timeout, Timeout.Infinite);
        }
        private void CallbackWrapper(object ev)
        {
            callback(ev);
            m_Parent.Remove(this);
        }

        public void Cancel()
        {
            m_Timer.Change(0, Timeout.Infinite);
        }
    };

    public class TimerCollection : CollectionBase
    {
        public void NewTimer(WarnEvents ev, TimerCallback callback, int timeout)
        {
            this.Add(new WarnTimer(this, ev, callback, timeout));
        }
        public int Add(WarnTimer item)
        {
            foreach (WarnTimer w in this)
            {
                if (item.Event == w.Event)
                {
                    w.Reset();
                    return IndexOf(w);
                }
            }
            return List.Add(item);
        }
        public void Insert(int index, WarnTimer item)
        {
            foreach (WarnTimer w in this)
            {
                if (item.Event == w.Event)
                {
                    w.Cancel();
                }
            }
            List.Insert(index, item);
        }
        public void Remove(WarnTimer item)
        {
            try
            {
                List.Remove(item);
            }
            catch { }
        }
        public bool Contains(WarnTimer item)
        {
            return List.Contains(item);
        }
        public int IndexOf(WarnTimer item)
        {
            return List.IndexOf(item);
        }
        public void CopyTo(WarnTimer[] array, int index)
        {
            List.CopyTo(array, index);
        }
        public WarnTimer this[int index]
        {
            get { return (WarnTimer)List[index]; }
            set { List[index] = value; }
        }
    }
}
